package com.lmy.androidcustomview.touch

import android.content.Context
import android.util.AttributeSet
import android.view.*
import android.widget.OverScroller
import androidx.core.view.children
import kotlin.math.abs


class TwoViewPager(context: Context, attrs: AttributeSet) : ViewGroup(context, attrs) {
    //记录down事件时的坐标
    private var downX = 0f
    private var downY = 0f

    //记录按下滑动的X轴距离
    private var downScrollX = 0f

    //判断是否在滑动状态
    private var scrolling = false

    //惯性滑动需要的
    private val overScroller: OverScroller = OverScroller(context)

    //包含用于UI的标准常量的方法，用于超时，大小和距离
    private val viewConfiguration: ViewConfiguration = ViewConfiguration.get(context)
    //最小和最大的快滑速度  在我们认为用户正在滚动整个页面之前，触摸可以漂移的距离（以像素为单位
    private var minVelocity = viewConfiguration.scaledMinimumFlingVelocity
    private var maxVelocity = viewConfiguration.scaledMaximumFlingVelocity
    private var pagingSlop = viewConfiguration.scaledPagingTouchSlop

    //初始化 计速器 用于惯性滑动的时候用的 初始速度
    private val velocityTracker = VelocityTracker.obtain()


    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        //让该视图的所有子级自己进行测量，把所有子View设置为父View 的大小
        measureChildren(widthMeasureSpec, heightMeasureSpec)
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
    }

    override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
        var childLeft = 0
        val childTop = 0
        var childRight = width
        val childBottom = height
        //摆放子View的位置 充满屏幕 下一个View的摆放位置在下一个View的后面
        for (child in children) {
            child.layout(childLeft, childTop, childRight, childBottom)
            childLeft += width
            childRight += width
        }
    }

    /**
     * 判断是不是要拦截
     * 存储一些初始状态
     */
    override fun onInterceptTouchEvent(event: MotionEvent): Boolean {
        if (event.actionMasked == MotionEvent.ACTION_DOWN) {
            //清除速度计算器 初始化
            velocityTracker.clear()
        }
        velocityTracker.addMovement(event)
        var result = false
        when (event.actionMasked) {
            MotionEvent.ACTION_DOWN -> {
                scrolling = false
                downX = event.x
                downY = event.y
                downScrollX = scrollX.toFloat()
            }
            /**
             * 根据滑动的距离是不是足够长 来判断要不要拦截
             */
            MotionEvent.ACTION_MOVE -> if (!scrolling) {
                val dx = downX - event.x
                if (abs(dx) > pagingSlop) {
                    scrolling = true
                    //当一个滑动控件拦截子View的事件时 此时就不想让父View在拦截本身(本次滑动序列) 调用下面的方法
                    parent.requestDisallowInterceptTouchEvent(true)
                    result = true
                }
            }
        }
        return result
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        if (event.actionMasked == MotionEvent.ACTION_DOWN) {
            velocityTracker.clear()
        }
        //把当前位置加进去velocityTracker
        velocityTracker.addMovement(event)
        when (event.actionMasked) {
            MotionEvent.ACTION_DOWN -> {
                downX = event.x
                downY = event.y
                downScrollX = scrollX.toFloat()
            }
            MotionEvent.ACTION_MOVE -> {
                /**
                 * 移动所有子View 正常应该是当前点的位置-落下点位置+初始按下滑动偏移量=滑动偏移量
                 * scrollTo 这个方法参数是相反的
                 * 落下点位置-当前点的位置+初始按下滑动偏移量=滑动偏移量
                 */
                val dx = (downX - event.x + downScrollX).toInt()
                    //设置最小滑动距离和最大滑动距离
                    .coerceAtLeast(0)
                    .coerceAtMost(width)
                scrollTo(dx, 0)
            }
            MotionEvent.ACTION_UP -> {
                //计算松手时的速度 掐表 单位时间内的速度 并设置速度上限 1000毫秒移动的像素数 像素/s
                velocityTracker.computeCurrentVelocity(1000, maxVelocity.toFloat())
                //取出x轴的速度值
                val vx = velocityTracker.xVelocity
                val scrollX = scrollX
                //如果速度快和速度慢来判断子View应该停靠的位置
                val targetPage = if (abs(vx) < minVelocity) {
                    /**
                     *如果速度<最小快滑 根据滑动距离是否超多View宽度的一半作为停靠标准
                     */
                    if (scrollX > width / 2) 1 else 0
                } else {
                    /**
                     *看看快滑的方向 正值右方 负值左方
                     */
                    if (vx < 0) 1 else 0
                }
                val scrollDistance = if (targetPage == 1) width - scrollX else -scrollX
                //设定目标位置 进行滑动
                overScroller.startScroll(getScrollX(), 0, scrollDistance, 0)
                //更新界面
                postInvalidateOnAnimation()
            }
        }
        return true
    }

    /**
     * postInvalidateOnAnimation会触发 ondraw方法
     * ondraw方法会触发computeScroll所以是一个闭合
     * 只需要判断滑动未结束的时候 就一直更新界面
     */
    override fun computeScroll() {
        if (overScroller.computeScrollOffset()) {
            scrollTo(overScroller.currX, overScroller.currY)
            postInvalidateOnAnimation()
        }
    }
}
